home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 025a / gsdb25.zip / GS_DBFLD.PAS < prev    next >
Pascal/Delphi Source File  |  1991-08-01  |  48KB  |  1,421 lines

  1. {                      dBase III Field Handler
  2.  
  3.        GS_DBFLD Copyright (c)  Richard F. Griffin
  4.  
  5.        15 November 1990
  6.  
  7.        102 Molded Stone Pl
  8.        Warner Robins, GA  31088
  9.  
  10.        -------------------------------------------------------------
  11.        This unit handles field processing for all dBase III file (.DBF)
  12.        operations.
  13.  
  14.                    SHAREWARE  -- COMMERCIAL USE RESTRICTED
  15.  
  16.  
  17.  
  18.        Changes:
  19.  
  20.        02 May 91 - Changed the type of value returned for a date field from
  21.                    string to longint.  The value assigned is the julian date.
  22.                    Note that the Julian day number is not the same as the
  23.                    serial day number (1-366) which is sometimes (erroneously)
  24.                    called a Julian date.  Refer to the GS_Date unit for more
  25.                    information.
  26.  
  27.        03 May 91 - Ensured Date field is a julian date for .NDX indexes in the
  28.                    IndexTo method.
  29.  
  30.        02 Jun 91 - Allowed a 'blank' date field to be acccepted if the field
  31.                    was originally blank in AcceptField.
  32.  
  33.        31 Jul 91 - Created a StatusUpdate virtual method to allow a user to
  34.                    track progress of actions such as Pack and IndexTo.  The
  35.                    status will be passed to StatusUpdate from within those
  36.                    methods.  The basic StatusUpdate is empty and does nothing
  37.                    with the passed status.  The user has the option to create
  38.                    his own virtual method to capture this information.
  39.  
  40.  
  41. }
  42. {
  43.                            ┌──────────────────────┐
  44.                            │  INTERFACE SECTION:  │
  45.                            └──────────────────────┘
  46. }
  47. unit GS_dBFld;
  48.  
  49. interface
  50.  
  51. uses
  52.    CRT,
  53.    GS_Date,
  54.    GS_Edit,
  55.    GS_FileH,
  56.    GS_Error,
  57.    GS_KeyI,
  58.    GS_Strng,
  59.    GS_Winfc,
  60.    GS_dBase;
  61.  
  62. const
  63.    StatusStart     = -1;
  64.    StatusStop      = 0;
  65.    StatusIndexTo   = 1;
  66.    StatusPack      = 2;
  67.  
  68. type
  69.    GS_dBFld_Objt   = object(GS_dBase_dB)
  70.       LastFldTyp   : char;            {Last FieldGet type field}
  71.       LastFldDec   : integer;         {Last FieldGet Decimals}
  72.       LastFldLth   : integer;         {Last FieldGet Length}
  73.       LastFldNam   : string[11];      {Last FieldGet Name}
  74.       LastFldNum   : integer;         {Last FieldGet Number}
  75.       EditOn       : boolean;         {Edit allowed}
  76.       RecChanged   : boolean;         {Flag for record changed}
  77.       Memo_Loc     : longint;         {Starting memo block for field}
  78.       Memo_Bloks   : integer;         {Number of blocks used for the field}
  79.       Memo_Store   : GS_Edit_Objt;    {Object to store/edit memos}
  80.       DeleteOnF9   : boolean;         {Flag to permit F9 to delete/undelete}
  81.  
  82.       Procedure Check_Func_Keys; virtual;
  83.       Function  Create(FName : string) : boolean;
  84.       function  DateGet(st : string) : longint;
  85.       function  DateGetN(n : integer) : longint;
  86.       Procedure DatePut(st : string; jdte : longint);
  87.       Procedure DatePutN(n : integer; jdte : longint);
  88.       Function  FieldAccept(st,Titl : string; x,y : integer) : string;
  89.       Procedure FieldDisplay(st,Titl : string; x,y : integer);
  90.       Function  FieldDisplayScreen : boolean;
  91.       Function  FieldGet(st : string) : string;
  92.       Function  FieldGetN(n : integer) : string;
  93.       Procedure FieldPut(st1, st2 : string);
  94.       Procedure FieldPutN(n : integer; st1 : string);
  95.       Function  FieldUpdateScreen : boolean;
  96.       Function  FieldAppendScreen(empty : boolean) : boolean;
  97.       Function  Formula(st : string; var ftyp : char) : string; virtual;
  98.       Function  HuntFieldName(st : string; var fs : integer) : boolean;
  99.       Procedure IndexTo(filname, formla : string);
  100.       Constructor Init(FName : string);
  101.       function  LogicGet(st : string) : boolean;
  102.       function  LogicGetN(n : integer) : boolean;
  103.       Procedure LogicPut(st : string; b : boolean);
  104.       Procedure LogicPutN(n : integer; b : boolean);
  105.       Procedure MemoEdit;
  106.       function  MemoGetLine(linenum : integer) : string;
  107.       procedure MemoGet(rpt : string);
  108.       Procedure MemoWidth(l : integer);
  109.       function  MemoLines : integer;
  110.       function  MemoPut : string;
  111.       function  NumberGet(st : string) : real;
  112.       function  NumberGetN(n : integer) : real;
  113.       Procedure NumberPut(st : string; r : real);
  114.       Procedure NumberPutN(n : integer; r : real);
  115.       Procedure Pack;
  116.       Procedure StatusUpdate(statword1,statword2,statword3 : longint); virtual;
  117.       function  StringGet(st : string) : string;
  118.       function  StringGetN(n : integer) : string;
  119.       Procedure StringPut(st1, st2 : string);
  120.       Procedure StringPutN(n : integer; st1 : string);
  121.    end;
  122.  
  123. implementation
  124.  
  125. procedure GS_dBFld_Objt.Check_Func_Keys;
  126. begin
  127.    case ch of
  128.      Kbd_F9   : begin
  129.                    if DeleteOnF9 then
  130.                    begin
  131.                       if RecNumber < 0 then
  132.                       begin
  133.                          if DelFlag then CurRecord^[0] :=  32
  134.                             else CurRecord^[0] := 42;
  135.                          DelFlag := not DelFlag;
  136.                       end
  137.                          else if DelFlag then UnDelete else Delete;
  138.                       GS_KeyI_Ret := true;
  139.                       Ch := Kbd_Ret;
  140.                    end else GS_dBase_DB.Check_Func_Keys;
  141.                 end;
  142.      Kbd_F10  : begin
  143.                    GS_KeyI_Ret := true;
  144.                    Ch := Kbd_Ret;
  145.                 end;
  146.      else GS_dBase_DB.Check_Func_Keys;
  147.   end;
  148. end;
  149.  
  150.  
  151. function  GS_dBFld_Objt.DateGet(st : string) : longint;
  152. var
  153.    t     : string;
  154.    v     : longint;
  155. begin
  156.    t := FieldGet(st);
  157.    v := GS_Date_Juln(t);
  158.    if v > 0 then DateGet := v else DateGet := 0;
  159. end;
  160.  
  161. function  GS_dBFld_Objt.DateGetN(n : integer) : longint;
  162. var
  163.    t     : string;
  164.    v     : longint;
  165. begin
  166.    t := FieldGetN(n);
  167.    v := GS_Date_Juln(t);
  168.    if v > 0 then DateGetN := v else DateGetN := 0;
  169. end;
  170.  
  171. Procedure GS_dBFld_Objt.DatePut(st : string; jdte : longint);
  172. var
  173.    f    : integer;
  174.    t    : string[8];
  175. begin
  176.    if not HuntFieldName(st,f) then
  177.    begin
  178.       ShowError(625,st);
  179.       exit;
  180.    end;
  181.    if jdte = 0 then t := '        '
  182.       else t := GS_Date_DBStor(jdte);
  183.    FieldPutN(f,t);
  184. end;
  185.  
  186. Procedure GS_dBFld_Objt.DatePutN(n : integer; jdte : longint);
  187. var
  188.    t    : string[8];
  189. begin
  190.    if n > NumFields then
  191.    begin
  192.       ShowError(627,'Field number out of range');
  193.       exit;
  194.    end;
  195.    if jdte = 0 then t := '        '
  196.       else t := GS_Date_DBStor(jdte);
  197.    FieldPutN(n,t);
  198. end;
  199.  
  200. function  GS_dBFld_Objt.LogicGet(st : string) : boolean;
  201. begin
  202.    LogicGet := ValLogic(FieldGet(st));
  203. end;
  204.  
  205. function  GS_dBFld_Objt.LogicGetN(n : integer) : boolean;
  206. begin
  207.    LogicGetN := ValLogic(FieldGetN(n));
  208. end;
  209.  
  210. Procedure GS_dBFld_Objt.LogicPut(st : string; b : boolean);
  211. begin
  212.    FieldPut(st,StrLogic(b));
  213. end;
  214.  
  215. Procedure GS_dBFld_Objt.LogicPutN(n : integer; b : boolean);
  216. begin
  217.    FieldPutN(n,StrLogic(b));
  218. end;
  219.  
  220. function  GS_dBFld_Objt.NumberGet(st : string) : real;
  221. var
  222.    r : integer;
  223.    v : real;
  224.    s : string;
  225. begin
  226.    s := TrimR(FieldGet(st));
  227.    r := 0;
  228.    if s = '' then v := 0 else val(s,v,r);
  229.    if r <> 0 then
  230.    begin
  231.       ShowError(620,'Not a valid numeric field in NumberGet'+s);
  232.       v := 0;
  233.    end;
  234.    NumberGet := v;
  235. end;
  236.  
  237. function  GS_dBFld_Objt.NumberGetN(n : integer) : real;
  238. var
  239.    r : integer;
  240.    v : real;
  241.    s : string;
  242. begin
  243.    s := TrimR(FieldGetN(n));
  244.    r := 0;
  245.    if s = '' then v := 0 else val(s,v,r);
  246.    if r <> 0 then
  247.    begin
  248.       ShowError(620,'Not a valid numeric field in NumberGetN - '+s);
  249.       v := 0;
  250.    end;
  251.    NumberGetN := v;
  252. end;
  253.  
  254. Procedure GS_dBFld_Objt.NumberPut(st : string; r : real);
  255. var
  256.    f : integer;
  257.    s : string;
  258. begin
  259.    if not HuntFieldName(st,f) then
  260.    begin
  261.       ShowError(625,st);
  262.       exit;
  263.    end;
  264.    Str(r:LastFldLth:LastFldDec,s);
  265.    FieldPutN(f,s);
  266. end;
  267.  
  268. Procedure GS_dBFld_Objt.NumberPutN(n : integer; r : real);
  269. var
  270.    s : string;
  271. begin
  272.    if n > NumFields then
  273.    begin
  274.       ShowError(627,'Field number out of range');
  275.       exit;
  276.    end;
  277.    Str(r:Fields^[n].FieldLen:Fields^[n].FieldDec,s);
  278.    FieldPutN(n,s);
  279. end;
  280.  
  281. function  GS_dBFld_Objt.StringGet(st : string) : string;
  282. begin
  283.    StringGet := TrimR(FieldGet(st));
  284. end;
  285.  
  286. function  GS_dBFld_Objt.StringGetN(n : integer) : string;
  287. begin
  288.    StringGetN := TrimR(FieldGetN(n));
  289. end;
  290.  
  291. Procedure GS_dBFld_Objt.StringPut(st1,st2 : string);
  292. begin
  293.    FieldPut(st1,st2);
  294. end;
  295.  
  296. Procedure GS_dBFld_Objt.StringPutN(n : integer; st1 : string);
  297. begin
  298.    FieldPutN(n,st1);
  299. end;
  300.  
  301. function GS_dBFld_Objt.HuntFieldName(st : string; var fs : integer) : boolean;
  302. var
  303.    FSt : string;
  304.    mtch : boolean;
  305. begin
  306.    FSt := AllCaps(st);             {Capitalize the workstring}
  307.    FSt := TrimR(FSt);              {Remove trailing spaces}
  308.    fs := 1;                        {Initialize field count}
  309.    mtch := false;                  {Set match found to false}
  310.    while (not mtch) and (fs <= NumFields) DO
  311.       if FieldsN^[fs] = FSt then mtch := true else inc(fs);
  312.    if mtch then
  313.    begin
  314.       LastFldTyp := Fields^[fs].FieldType;
  315.       LastFldDec := Fields^[fs].FieldDec;
  316.       LastFldLth := Fields^[fs].FieldLen;
  317.    end;
  318.    HuntFieldName := mtch;
  319. end;
  320.  
  321. Function GS_dBFld_Objt.Create(FName : string) : boolean;
  322. begin
  323.    if GS_dBase_DB.Create(FName) then
  324.    begin
  325.       Init(FName);
  326.       Create := true;
  327.    end else Create := false;
  328. end;
  329.  
  330. Procedure GS_dBFld_Objt.Pack;
  331. const
  332.    EOFMark : Byte = $1A;
  333. var
  334.    df   : file;                       {Local file variable for memo work file}
  335.    mbuf : array[0..GS_dBase_MaxMemoRec] of byte;
  336.    rsl  : word;
  337.    i, j : longint;                    {Local variables   }
  338.    mcnt,
  339.    tcnt : longint;
  340.    done : boolean;
  341.    rl   : real;
  342.    FNam : string[64];
  343.  
  344.    procedure UpdateMemo;
  345.    var
  346.       fp : integer;
  347.    begin
  348.       for fp := 1 to NumFields do
  349.       begin
  350.          if Fields^[fp].FieldType = 'M' then
  351.          begin
  352.             Memo_Loc := Trunc(NumberGetN(fp));
  353.             Memo_Bloks := 0;          {Initialize blocks read}
  354.             if (Memo_Loc <> 0) then
  355.             begin
  356.                tcnt := GS_FileSize(df);
  357.                rl := tcnt;
  358.                NumberPutN(fp,rl);
  359.                 done := false;         {Reset done flag to false}
  360.                while (not done) do    {loop until done (EOF mark)}
  361.                begin
  362.                   GS_FileRead(mFile, Memo_Loc+Memo_Bloks, mbuf, 1, rsl);
  363.                   inc(Memo_Bloks);
  364.                   mCnt := 0;          {Counter into disk read buffer}
  365.                   while (mCnt < GS_dBase_MaxMemoRec) and (done = false) do
  366.                   begin
  367.                      if mbuf[mcnt] = $1A then done := true;
  368.                      inc (mcnt);
  369.                   end;
  370.                   if not done then GS_FileWrite(df,-1,mbuf,1, rsl);
  371.                end;
  372.                FillChar(mbuf[mcnt],GS_dBase_MaxMemoRec - mcnt,#0);
  373.                GS_FileWrite(df,-1,mbuf,1, rsl);
  374.                                       {Write the last block to the .DBT}
  375.             end;
  376.          end;
  377.       end;
  378.    end;
  379.  
  380. begin      {Pack}
  381.    StatusUpdate(StatusStart,StatusPack,NumRecs);
  382.    i := 1;
  383.    while dbfNdxTbl[i] <> nil do
  384.    begin
  385.       dbfNdxTbl[i]^.Ndx_Close;
  386.       Dispose(dbfNdxTbl[i]);
  387.       dbfNdxTbl[i] := nil;
  388.       inc(i);
  389.    end;
  390.    dbfNdxActv := false;               {Set index active flag to false}
  391.    j := 0;
  392.    if WithMemo then
  393.    begin
  394.       GS_FileAssign(df,'DB3$$$.D$$',2048);
  395.       GS_FileRewrite(df,GS_dBase_MaxMemoRec);
  396.       FillChar(mbuf,GS_dBase_MaxMemoRec,#0);
  397.       mbuf[0] := 1;
  398.       GS_FileWrite(df,0,mbuf,1,rsl);
  399.    end;
  400.    for i := 1 to NumRecs do           {Read .DBF sequentially}
  401.    begin
  402.       GetRec(i);
  403.       if not DelFlag then             {Write to work file if not deleted}
  404.       begin
  405.          inc(j);                      {Increment record count for packed file }
  406.          if WithMemo then UpdateMemo;
  407.          PutRec(j);
  408.       end;
  409.       StatusUpdate(StatusPack,i,0);
  410.    end;
  411.    if i > j then                      {If records were deleted then...}
  412.    begin
  413.       NumRecs := j;                   {Store new record count in objectname}
  414.       GS_FileWrite(dfile, HeadLen+(j*RecLen)+1, EOFMark, 1, rsl);
  415.                                       {Write End of File byte at file end}
  416.       GS_FileTruncate(dfile,HeadLen+(j*RecLen)+1);
  417.                                       {Set new file size for dBase file};
  418.    end;
  419.    if WithMemo then
  420.    begin
  421.       tcnt := GS_FileSize(df);
  422.       FillChar(mbuf,GS_dBase_MaxMemoRec,#0);
  423.       Move(tcnt,mbuf[0],4);
  424.       GS_FileWrite(df,0,mbuf,1, rsl);
  425.                                       {Write the block to the .DBT.  It will}
  426.                                       {point to the next available block};
  427.       FNam := FileName;
  428.       FNam[length(FNam)] := 'T';
  429.       GS_FileClose(mFile);
  430.       GS_FileClose(df);
  431.       GS_FileErase(mFile);            {Erase original file}
  432.       GS_FileRename(df, FNam);        {Rename work file to original file name}
  433.       GS_FileAssign(mFile, FNam, 2048); {Set file type to new file}
  434.       GS_FileReset(mFile, GS_dBase_MaxMemoRec);
  435.    end;
  436.    StatusUpdate(StatusStop,0,0);
  437. END;                        { Pack }
  438.  
  439. Function GS_dBFld_Objt.FieldAccept(st,Titl : string; x,y : integer) : string;
  440. var
  441.    txtatrb,
  442.    i,
  443.    v         :  integer;              {Counter variables}
  444.    t         :  string[255];          {Work string to hold default (old) value}
  445.    f         : string[2];
  446.  
  447.    Procedure AcceptC;
  448.    var
  449.       r_c : string;
  450.    begin
  451.       GS_Wind_SetIVMode;
  452.       if EditOn then        {If edit permitted, then go edit string}
  453.       begin
  454.          r_c := t;
  455.          t := EditString(t, v, y, LastFldLth);
  456.          if t <> r_c then RecChanged := true;
  457.       end
  458.       else
  459.       begin
  460.          gotoxy(v,y);       {Go to start of field screen position}
  461.          write(t,'':LastFldLth-length(t));
  462.                             {Rewrite the string on screen inverted}
  463.          WaitForKey;
  464.       end;
  465.       GS_Wind_SetNmMode;
  466.       gotoxy(v,y);          {Go to start of field screen position}
  467.       write(t,'':LastFldLth-length(t));
  468.                             {Rewrite the string on screen in the original color}
  469.    end;
  470.  
  471.    Procedure AcceptD;
  472.    var
  473.       okDate : boolean;
  474.       v1,
  475.       v2     : longint;
  476.       h1     : string[10];
  477.    begin
  478.       t := TrimR(t);
  479.       if length(t) <> 8 then
  480.       begin
  481.          t := '  /  /    ';
  482.          if not GS_Date_Century then t[0] := #8;
  483.       end
  484.       else
  485.       begin
  486.          v1 := GS_Date_Juln(t);
  487.          t := GS_Date_View(v1);
  488.       end;
  489.       h1 := t;
  490.       LastFldLth := length(t);
  491.       okDate := false;
  492.       repeat
  493.          AcceptC;
  494.          if EditOn then
  495.          begin
  496.             if GS_KeyI_Esc then v2 := v1
  497.                else v2 := GS_Date_Juln(t);
  498.             if v2 >= 0 then
  499.             begin
  500.                okDate := true;
  501.                t := GS_Date_DBStor(v2);
  502.             end
  503.             else
  504.             begin
  505.                if t = h1 then
  506.                begin
  507.                   t := FieldGet(st);
  508.                   okDate := true;
  509.                end;
  510.             end;
  511.          end else okDate := true;
  512.          if not okDate then SoundBell(BeepTime,BeepFreq);
  513.       until okDate;
  514.    end;
  515.  
  516.    Procedure AcceptL;
  517.    var
  518.       data : string[1];
  519.    begin
  520. {
  521.                     ┌─────────────────────────────────────┐
  522.                     │  Accept keyboard entry.  Loop until │
  523.                     │  value is T,t,Y,y,F,f,N,n.          │
  524.                     └─────────────────────────────────────┘
  525. }
  526.       repeat
  527.          if t = '' then t := 'F';
  528.          AcceptC;
  529.          if not EditOn then exit;
  530.          if t[1] in ['T','t','Y','y','F','f','N','n'] then
  531.          begin end else SoundBell(BeepTime,BeepFreq);
  532.       until t[1] in ['T','t','Y','y','F','f','N','n'];
  533.       if t[1] in ['T','t','Y','y'] then t[1] := 'T' else t[1] := 'F';
  534.    end;
  535.  
  536.    procedure AcceptM;
  537.    var
  538.       ans       :  string[10];        {Work string to hold edit value}
  539.       r_c       :  string[10];        {Work string for memo block number}
  540.    begin
  541.       GS_Wind_SetIvMode;
  542.       ans := 'N';                     {Initialize ans to false}
  543.       if EditOn then write('  Edit ? ') else write('  View ? ');
  544.       repeat
  545.          ans := EditString(ans,v+9,y,1);
  546.                                       {Go edit string t for 1 character}
  547.                                       {at cursor position v,y}
  548.          if ans[1] in ['T','t','Y','y','F','f','N','n'] then
  549.             begin end else SoundBell(BeepTime,BeepFreq);
  550.       until ans[1] in ['T','t','Y','y','F','f','N','n'];
  551.       GS_Wind_SetNmMode;              {Restore original text attribute}
  552.       gotoxy(v,y);                    {Now reset to 'memo' for field name}
  553.       write('---memo---');
  554.       if ans[1] in ['T','t','Y','y'] then
  555.       begin
  556.          r_c := t;
  557.          MemoGet(t);
  558.          If EditOn then Memo_Store.Edit else Memo_Store.View;
  559.          if (EditOn) and (GS_KeyI_Esc) then
  560.          begin
  561.             GS_KeyI_Esc := false;     {Reset Escape flag so its not used}
  562.                                       {elsewhere}
  563.             GS_KeyI_Chr := ' ';
  564.             MemoGet(t);
  565.          end
  566.          else
  567.          begin
  568.             GS_KeyI_Chr := ' ';       {Clear character last entered}
  569.             if EditOn then t := MemoPut;
  570.             if t <> r_c then RecChanged := true;
  571.          end;
  572.       end;
  573.    end;
  574.  
  575.    Procedure AcceptN;
  576.    var
  577.       data : string;
  578.       i   : integer;
  579.       r   : real;
  580.    begin
  581. {
  582.                     ┌─────────────────────────────────────┐
  583.                     │  Accept keyboard entry.  Loop until │
  584.                     │  value is Numeric.                  │
  585.                     └─────────────────────────────────────┘
  586. }
  587.       repeat
  588.          if t = '' then Str(0.0:LastFldLth:LastFldDec,t);
  589.          AcceptC;
  590.          if not EditOn then exit;
  591.          val(t, r, i);
  592.          if i = 0 then
  593.          begin
  594.             Str(r:LastFldLth:LastFldDec,t);
  595.             if length(t) > LastFldLth then i := 999;
  596.          end;
  597.          if i <> 0 then
  598.          begin
  599.             SoundBell(BeepTime,BeepFreq);
  600.             t := '';
  601.          end;
  602.       until i = 0;                    {i will be 0 when data is a valid number}
  603.       gotoxy(v,y);          {Go to start of field screen position}
  604.       write(t,'':LastFldLth-length(t));
  605.                             {Rewrite the string on screen in the original color}
  606.    end;
  607.  
  608. begin
  609.    GotoXY(x,y);                       {Go to position on screen}
  610.    write(Titl);                       {Write the title of field}
  611.    v := WhereX;                       {Save the position after writing title}
  612.    t := TrimR(FieldGet(st));          {Get the field in the work string}
  613.    case LastFldTyp of
  614.       'C'  : begin
  615.                 AcceptC;
  616.                 FieldAccept := t;     {Return the string to calling routine}
  617.              end;
  618.       'D'  : begin
  619.                 AcceptD;
  620.                 FieldAccept := t;
  621.              end;
  622.       'L'  : begin
  623.                 AcceptL;
  624.                 FieldAccept := t;
  625.              end;
  626.       'M'  : begin
  627.                 AcceptM;
  628.                 FieldAccept := t;
  629.              end;
  630.       'N'  : begin
  631.                 AcceptN;
  632.                 FieldAccept := t;
  633.              end;
  634.    end;
  635. end;
  636.  
  637. Procedure GS_dBFld_Objt.FieldDisplay(st,Titl : string; x,y : integer);
  638. var
  639.    i,
  640.    v         :  integer;              {Counter variables}
  641.    t         :  string[255];          {Work string to hold default (old) value}
  642.    data      :  string[10];
  643. begin
  644.    GotoXY(x,y);                       {Go to position on screen}
  645.    write(Titl);                       {Write the title of field}
  646.    v := WhereX;                       {Save the position after writing title}
  647.    t := TrimR(FieldGet(st));          {Get the field in the work string}
  648.  
  649.    case LastFldTyp of
  650.       'C',
  651.       'L'  : begin
  652.                 gotoxy(v,y);          {Go to start of field screen position}
  653.                 write(t,'':LastFldLth-length(t));
  654.                                       {Write the string on screen }
  655.              end;
  656.       'D'  : begin
  657.                 t := GS_Date_View(GS_Date_Juln(t));;
  658.                 write(t);
  659.              end;
  660.       'N'  : begin
  661.                 if t = '' then t := '0';
  662.                 gotoxy(v,y);          {Go to start of field screen position}
  663.                 write(t:LastFldLth);
  664.              end;
  665.       'M'  : begin
  666.                 gotoxy(v,y);          {Go to start of field screen position}
  667.                 write('---memo---');  {Write the '---memo--- on screen }
  668.              end;
  669.    end;
  670. end;
  671.  
  672. Function GS_dBFld_Objt.FieldDisplayScreen : boolean;
  673. var
  674.    f,
  675.    h     : boolean;
  676. begin
  677.    h := EditOn;
  678.    EditOn := false;
  679.    f := FieldUpdateScreen;
  680.    EditOn := h;
  681.    FieldDisplayScreen := f;
  682. end;
  683.  
  684. function GS_dBFld_Objt.FieldGetN(n : integer) : String;
  685. var
  686.    os,
  687.    fs  : longint;
  688.    i,
  689.    k   : integer;
  690.    FSt,
  691.    WSt : string[255];
  692.    NSt : string[10];
  693. begin
  694.    fs := n;                        {Initialize field count}
  695.    if (fs <= NumFields) then
  696.    BEGIN
  697.       os := 1;
  698.       WITH Fields^[fs] DO
  699.       BEGIN
  700.          CnvAscToStr(FieldName,FSt,11);
  701.          FSt := TrimR(FSt);           {Remove trailing spaces}
  702.          move(CurRecord^[FieldAddress], WSt[1], FieldLen);
  703.          WSt[0] := char(FieldLen);    {Set string length to field length}
  704.          FieldGetN := WSt;
  705.          LastFldTyp := FieldType;
  706.          LastFldDec := FieldDec;
  707.          LastFldLth := FieldLen;
  708.          LastFldNum := fs;
  709.          LastFldNam := FSt;
  710.       end;
  711.    end else
  712.    begin
  713.       str(n,NSt);
  714.       ShowError(603,NSt);
  715.       FieldGetN := '';
  716.       LastFldTyp := ' ';
  717.       LastFldDec := 0;
  718.       LastFldLth := 0;
  719.       LastFldNum := 0;
  720.       LastFldNam := '';
  721.    end;
  722. end;
  723.  
  724. function GS_dBFld_Objt.FieldGet(st : string) : String;
  725. var
  726.    fs : integer;
  727. begin
  728.    if HuntFieldName(st,fs) then FieldGet := FieldGetN(fs)
  729.    else
  730.    begin
  731.       ShowError(602,st);
  732.       FieldGet := '';
  733.       LastFldTyp := ' ';
  734.       LastFldDec := 0;
  735.       LastFldLth := 0;
  736.       LastFldNum := 0;
  737.       LastFldNam := '';
  738.    end;
  739. end;
  740.  
  741.  
  742. Procedure GS_dBFld_Objt.FieldPutN(n : integer; st1 : string);
  743. var
  744.    os,
  745.    fs  : longint;
  746.    i,
  747.    k   : integer;
  748.    FSt,
  749.    WSt : string[255];
  750.    NSt : string[10];
  751. begin
  752.    fs := n;                        {Initialize field count}
  753.    if (fs <= NumFields) then
  754.    BEGIN
  755.       WITH Fields^[fs] DO
  756.       BEGIN
  757.          move(FieldName,FSt[1],11);
  758.          FSt[0] := #11;
  759.          FSt[0] := char(pred(pos(#0,FSt)));
  760.          FSt := TrimR(FSt);        {Remove trailing spaces}
  761.          FillChar(CurRecord^[FieldAddress], FieldLen, ' ');
  762.          k := length(st1);         {Get length of input string}
  763.          if k > FieldLen then k := FieldLen;
  764.          Move(st1[1], CurRecord^[FieldAddress], k);
  765.          LastFldTyp := FieldType;
  766.          LastFldDec := FieldDec;
  767.          LastFldLth := FieldLen;
  768.          LastFldNum := fs;
  769.          LastFldNam := FSt;
  770.       end;
  771.    end else
  772.    begin
  773.       str(n,NSt);
  774.       ShowError(605,NSt);
  775.       LastFldTyp := ' ';
  776.       LastFldDec := 0;
  777.       LastFldLth := 0;
  778.       LastFldNum := 0;
  779.       LastFldNam := '';
  780.    end;
  781. end;
  782.  
  783. Procedure GS_dBFld_Objt.FieldPut(st1, st2 : string);
  784. var
  785.    fs : integer;
  786. begin
  787.    if HuntFieldName(st1,fs) then FieldPutN(fs,st2)
  788.    else
  789.    begin
  790.       ShowError(604,st1);
  791.       LastFldTyp := ' ';
  792.       LastFldDec := 0;
  793.       LastFldLth := 0;
  794.       LastFldNum := 0;
  795.       LastFldNam := '';
  796.    end;
  797. end;
  798.  
  799. Function GS_dBFld_Objt.FieldUpdateScreen : boolean;
  800. var
  801.    b,
  802.    i,
  803.    v,
  804.    x,
  805.    y,
  806.    ll    : integer;
  807.    st,
  808.    s     : string[12];
  809.    t     : string;
  810.    activlin,
  811.    activfld : integer;
  812.  
  813.  
  814.    Procedure UpdatePage;
  815.    var
  816.       validcmd : boolean;
  817.    begin
  818.       validcmd := false;
  819.       if activfld < b then activfld := b;
  820.       if activfld >= b+v then activfld := pred(b+v);
  821.       activlin := succ(activfld - b);
  822.       if (activlin < 1) or (activlin > v) then activlin := 1;
  823.       repeat
  824.          t := FieldAccept(FieldsN^[activfld],'',13,activlin);
  825.          if (EditOn) and (not GS_KeyI_Esc) then FieldPutN(activfld,t);
  826.          if (not GS_KeyI_Fuc) and (GS_KeyI_Chr >= #32) then
  827.             GS_KeyI_Chr := Kbd_Ret;
  828.  
  829.             case GS_KeyI_Chr of
  830.                Kbd_F9 :   begin
  831.                              gotoxy(3,ll);
  832.                              GS_Wind_SetIvMode;
  833.                              if DelFlag then write('Deleted')
  834.                                 else write('':8);
  835.                              GS_Wind_SetNmMode;
  836.                           end;
  837.                Kbd_PgUp : begin
  838.                              if activfld = b then
  839.                              begin
  840.                                 b := b-v;
  841.                                 if b < 1 then b := 1;
  842.                                 validcmd := true;
  843.                              end
  844.                              else activfld := b;
  845.                           end;
  846.                Kbd_PgDn : begin
  847.                              if activfld = pred(b+v) then
  848.                              begin
  849.                                 b := b+v;
  850.                                 if b > NumFields-v then b := succ(NumFields-v);
  851.                                 if b < 1 then b := 1;
  852.                                 validcmd := true;
  853.                              end
  854.                              else activfld := pred(b+v);
  855.                           end;
  856.                Kbd_UpAr : begin
  857.                              dec(activfld);
  858.                              if activfld < b then
  859.                              begin
  860.                                 dec(b);
  861.                                 if b < 1 then b := 1;
  862.                                 validcmd := true;
  863.                              end;
  864.                           end;
  865.                Kbd_RtAr,
  866.                Kbd_Tab,
  867.                Kbd_Ret,
  868.                Kbd_DnAr : begin
  869.                              inc(activfld);
  870.                              if activfld > pred(b+v) then
  871.                              begin
  872.                                 if activfld > NumFields then
  873.                                    activfld := NumFields
  874.                                 else
  875.                                 begin
  876.                                    inc(b);
  877.                                    if b > NumFields then
  878.                                       b := succ(NumFields-v);
  879.                                    validcmd := true;
  880.                                 end;
  881.                              end;
  882.                           end;
  883.                Kbd_Esc,
  884.                Kbd_F10  : validcmd := true;
  885.             end;
  886.  
  887.          if activfld < b then activfld := b;
  888.          if activfld >= b+v then activfld := pred(b+v);
  889.          activlin := succ(activfld - b);
  890.          if (activlin < 1) or (activlin > v) then activlin := 1;
  891.       until validcmd;
  892.    end;
  893.  
  894. begin
  895.    ClrScr;
  896.    DeleteOnF9 := true;
  897.    RecChanged := false;
  898.    b := 1;
  899.    activfld := b;
  900.    ll := succ(hi(WindMax)-hi(WindMin));
  901.    v := pred(ll);
  902.    GS_Wind_SetIvMode;
  903.    gotoxy(2,ll);
  904.    write('':pred(lo(WindMax)-lo(WindMin)));
  905.    if EditOn then
  906.    begin
  907.       if RecNumber < 0 then           {If Append, do the following}
  908.       begin
  909.          gotoxy(12,ll);
  910.          write('Append ');
  911.          write('EOF/',NumRecs);
  912.       end
  913.       else
  914.       begin                           {If Update do the following}
  915.          gotoxy(12,ll);
  916.          write('Update ');
  917.          write(RecNumber,'/',NumRecs);
  918.       end;
  919.    end else
  920.    begin                              {If Display then do this}
  921.       gotoxy(12,ll);
  922.       write('Display ');
  923.       write(RecNumber,'/',NumRecs);
  924.    end;
  925.    if DelFlag then
  926.    begin
  927.       gotoxy(3,ll);
  928.       write('Deleted');
  929.    end;
  930.    GS_Wind_SetNmMode;
  931.    if NumFields < v then v := NumFields;
  932.    x := 1;
  933.    y := 1;
  934.    Ch := ' ';
  935.    repeat
  936.       for i := b to pred(b+v) do
  937.       begin
  938.          s := FieldsN^[i];
  939.          FillChar(st[1],12,' ');
  940.          move(s[1],st[11-length(s)],length(s));
  941.          st[11] := ':';
  942.          st[0] := #12;
  943.          FieldDisplay(s,st,x,y);
  944.          case LastFldTyp of
  945.            'M' : begin
  946.                     gotoxy(x+12,y);
  947.                     write('---memo---');
  948.                     if RecNumber < 0 then FieldPutN(LastFldNum,' ');
  949.                                       {If Append, make sure memo field is not}
  950.                                       {pointing to a memo block              }
  951.                  end;
  952.          end;
  953.          ClrEol;
  954.          inc(y);
  955.       end;
  956.       UpdatePage;
  957.       y := 1;
  958.    until (GS_KeyI_Chr in [Kbd_Esc,Kbd_F10]) or
  959.          ((GS_KeyI_Chr = Kbd_PgUp) and (activfld = 1)) or
  960.          ((GS_KeyI_Chr = Kbd_PgDn) and (activfld = NumFields));
  961.    DeleteOnF9 := false;
  962.    if GS_KeyI_Chr in [Kbd_F10, Kbd_PgUp, Kbd_PgDn] then
  963.       FieldUpdateScreen := true
  964.    else FieldUpdateScreen := false;
  965. end;
  966.  
  967. Function GS_dBFld_Objt.FieldAppendScreen(empty : boolean) : boolean;
  968. begin
  969.    if empty then Blank;
  970.    CurRecord^[0] := 32;                   {Ensure delete flag is off}
  971.    DelFlag := false;
  972.    RecNumber := -1;
  973.    FieldAppendScreen := FieldUpdateScreen;
  974. end;
  975.  
  976. Function GS_dBFld_Objt.Formula(st : string; var ftyp : char) : string;
  977. var
  978.    FldVal,
  979.    FldWrk : string;
  980.    FldPos : integer;
  981.  
  982.    function HuntField(fldst : string) : String;
  983.    var
  984.       fs   : integer;
  985.       ss   : string;
  986.       FSt  : string;
  987.       mtch : boolean;
  988.    begin
  989.       FSt := AllCaps(fldst);          {Capitalize the workstring}
  990.       FSt := TrimR(FSt);              {Remove trailing spaces}
  991.       fs := 1;                        {Initialize field count}
  992.       mtch := false;                  {Set match found to false}
  993.       while (not mtch) and (fs <= NumFields) DO
  994.          if FieldsN^[fs] = FSt then mtch := true else inc(fs);
  995.       if mtch then
  996.       begin
  997.          WITH Fields^[fs] DO
  998.          BEGIN
  999.             move(CurRecord^[FieldAddress], FSt[1], FieldLen);
  1000.             FSt[0] := char(FieldLen);    {Set string length to field length}
  1001.             ftyp := FieldType;
  1002.             HuntField := FSt;
  1003.          end;
  1004.       end
  1005.       else
  1006.       begin
  1007.          ss := TrimL(fldst);
  1008.          if ss = '' then
  1009.          begin
  1010.             HuntField := '';
  1011.             exit;
  1012.          end;
  1013.          if ss[1] = '"' then
  1014.          begin
  1015.             ss := TrimR(ss);
  1016.             system.delete(ss,1,1);
  1017.             if ss[length(ss)] = '"' then ss[0] := chr(pred(length(ss)));
  1018.             HuntField := ss;
  1019.             exit;
  1020.          end;
  1021.          ShowError(601,st+' ('+fldst+')');
  1022.          HuntField  := '';
  1023.       end;
  1024.    end;
  1025.  
  1026. begin
  1027.    FldVal := '';                      {Initialize the return string value}
  1028.    FldWrk := st;                      {Move the input string to a work field}
  1029.    while FldWrk <> '' do              {Repeat while there is still something}
  1030.                                       {in the work field.}
  1031.    begin
  1032.       FldPos := pos('+', FldWrk);     {Search for a '+' delimiter}
  1033.       if FldPos = 0 then FldPos := length(FldWrk)+1;
  1034.                                       {If no '+' then simulate for this pass}
  1035.                                       {by setting position to one beyond the}
  1036.                                       {end of the target field string.}
  1037.       FldVal := FldVal + HuntField(SubStr(FldWrk,1,FldPos-1));
  1038.                                       {Go find the field using the substring}
  1039.                                       {from the string's beginning to one }
  1040.                                       {position before the '+' character.}
  1041.       system.delete(FldWrk,1,FldPos); {Delete the string up through the '+'};
  1042.       FldWrk := TrimL(FldWrk);        {Remove leading spaces}
  1043.    end;
  1044.    Formula := FldVal;                 {Return value to calling routine}
  1045. end;
  1046.  
  1047. Procedure GS_dBFld_Objt.IndexTo(filname, formla : string);
  1048. var
  1049.    i,
  1050.    j,
  1051.    fl : integer;                      {Local working variable}
  1052.    ft : char;
  1053.    ftyp : char;
  1054.    fval : longint;
  1055.    fkey : string;
  1056.  
  1057. {
  1058.              ┌──────────────────────────────────────────────────┐
  1059.              │  This routine will accumulate the field length   │
  1060.              │  of all fields passes in the calling argument.   │
  1061.              │  This is needed to pass the formula length to    │
  1062.              │  create the index header.                        │
  1063.              └──────────────────────────────────────────────────┘
  1064. }
  1065.  
  1066.  
  1067.    procedure AccumField;
  1068.    var
  1069.       FldWrk : string;
  1070.       FldLoc,
  1071.       FldPos : integer;
  1072.    begin
  1073.       ft := '*';                      {Set field type to new '*'}
  1074.       fl := 0;                        {initialize field length}
  1075.       FldWrk := TrimR(formla);        {Remove trailing spaces from argument}
  1076.       while FldWrk <> '' do           {Repeat while there is still something}
  1077.                                       {in the work field.}
  1078.       begin
  1079.          FldPos := pos('+', FldWrk);  {Search for a '+' delimiter}
  1080.          if FldPos = 0 then FldPos := length(FldWrk)+1;
  1081.                                       {If no '+' then simulate for this pass}
  1082.                                       {by setting position to one beyond the}
  1083.                                       {end of the target field string.}
  1084.  
  1085.                                       {Go find the field using the substring}
  1086.                                       {from the string's beginning to one }
  1087.                                       {position before the '+' character.}
  1088.         if not HuntFieldName(SubStr(FldWrk,1,FldPos-1),FldLoc) then
  1089.          begin
  1090.             fl := 0;
  1091.             exit;
  1092.          end;
  1093.          if ft = '*' then ft := LastFldTyp
  1094.             else ft := 'C';           {Set type to C if more than one field}
  1095.                                       {Else save this field's type         }
  1096.          fl := fl + Fields^[FldLoc].FieldLen;
  1097.                                       {If a valid field, then add the field}
  1098.                                       {length to the total field length value.}
  1099.          system.delete(FldWrk,1,FldPos);
  1100.                                       {Delete the string up through the '+'};
  1101.          FldWrk := TrimL(FldWrk);     {Remove leading spaces}
  1102.       end;
  1103.    end;
  1104.  
  1105. {
  1106.              ┌──────────────────────────────────────────────────┐
  1107.              │  Main routine.  This takes and analyzes the      │
  1108.              │  argument to build an index file.  It does the   │
  1109.              │  following:                                      │
  1110.              │  1.  Reset current index files.                  │
  1111.              │  2.  Get the total new formula field length.     │
  1112.              │  3.  Create an index file.                       │
  1113.              │  4.  Build the index by reading all dbase        │
  1114.              │      records and updating the index file.        │
  1115.              └──────────────────────────────────────────────────┘
  1116. }
  1117.  
  1118. begin
  1119.    StatusUpdate(StatusStart,StatusIndexTo,NumRecs);
  1120.    i := 1;
  1121.    while dbfNdxTbl[i] <> nil do
  1122.    begin
  1123.       dbfNdxTbl[i]^.Ndx_Close;
  1124.       Dispose(dbfNdxTbl[i]);
  1125.       dbfNdxTbl[i] := nil;
  1126.       inc(i);
  1127.    end;
  1128.    dbfNdxActv := false;               {Set index active flag to false}
  1129.    if formla <> '' then
  1130.    begin
  1131.       AccumField;                     {Get field length of the formula}
  1132.       if fl = 0 then
  1133.       begin
  1134.          ShowError(601,formla);       {Display Error if formula is bad}
  1135.          exit;                        {Exit if formula is no good}
  1136.       end;
  1137.       New(dbfNdxTbl[1]);              {Create a new index object}
  1138.       dbfNdxTbl[1]^.Ndx_Make(filname, formla, fl, ft);
  1139.                                       {Go create an index}
  1140.       Open;
  1141.       GetRec(Top_Record);             {Read all dBase file records}
  1142.       while not File_EOF do
  1143.       begin
  1144.          fkey := Formula(formla,ftyp);
  1145.          if (IsDB3NDX) and (ftyp = 'D') then
  1146.          begin
  1147.             fval := GS_Date_Juln(fkey);
  1148.             str(fval,fkey);
  1149.          end;
  1150.          dbfNdxTbl[1]^.KeyUpdate(fkey,RecNumber,-1);
  1151.                                       {Insert record in the index}
  1152.          StatusUpdate(StatusIndexTo,RecNumber,0);
  1153.          GetRec(Next_Record);
  1154.       end;
  1155. {      dbfNdxTbl[1]^.KeyList('PRN');}
  1156.       dbfNdxActv := true;             {Set index active flag true if index }
  1157.       GetRec(Top_Record);             {Reset to top record}
  1158.    end;
  1159.    StatusUpdate(StatusStop,0,0);
  1160. end;
  1161.  
  1162. constructor GS_dBFld_Objt.Init(FName : string);
  1163. begin
  1164.    EditOn := true;
  1165.    GS_dBase_DB.Init(FName);
  1166.    Memo_Store.Init;                   {Initialize the edit object}
  1167.    Memo_Store.Edit_Lgth := 50;        {Set default memo line size to 50}
  1168.    Wait_Cr := false;                  {Set EditString not to wait for CR}
  1169.    DeleteOnF9 := false;               {Turn off F9 for delete/undelete}
  1170. end;
  1171.  
  1172. function GS_dBFld_Objt.MemoGetLine(linenum : integer) : string;
  1173. begin
  1174.    if linenum > Memo_Store.Total_Lines then
  1175.    begin
  1176.       MemoGetLine := '';
  1177.       exit;
  1178.    end;
  1179.    if not Memo_Store.Find_Line(linenum) then
  1180.    begin
  1181.       MemoGetLine := '';
  1182.       exit;
  1183.    end;
  1184.    MemoGetLine := Memo_Store.Work_line^.Valu_Line;
  1185. end;
  1186.  
  1187. Procedure GS_dBFld_Objt.MemoGet(rpt : string);
  1188. const
  1189.    EOFMark : byte = $1A;              {End of disk file code}
  1190.  
  1191. var
  1192.    cnt,                               {Counter for memo storage location}
  1193.    lCnt,                              {Counter for line length in characters}
  1194.    mCnt    : longint;                 {Counter for input buffer char position}
  1195.    Result  : word;                    {BlockRead number of bytes read}
  1196.    done    : boolean;                 {Flag set when end of memo field found}
  1197.    i,j     : integer;                 {Working variable}
  1198.    Mem_Block : array [0..GS_dBase_MaxMemoRec] of byte;
  1199.                                       {Input buffer}
  1200. BEGIN                       { Get Memo Field }
  1201.    Val(rpt, Memo_Loc, i);             {Save starting block number}
  1202.    Memo_Bloks := 0;                   {Initialize blocks read}
  1203.    Memo_Store.Clear_Editor;           {Begin memo line count at zero}
  1204. {
  1205.                     ┌─────────────────────────────────────┐
  1206.                     │  If no .DBT memo field for this     │
  1207.                     │  record, then exit.                 │
  1208.                     └─────────────────────────────────────┘
  1209. }
  1210.    if (Memo_Loc = 0) then exit;
  1211.    Memo_Store.Work_Line := Memo_Store.Get_Line_Mem(Memo_Store.Edit_Lgth);
  1212.                                       {Get the first edit line record}
  1213.    Memo_Store.Active_Line := 1;       {Set active line to first line}
  1214.    done := false;                     {Reset done flag to false}
  1215.    cnt := 0;                          {index into Memo_Store buffer}
  1216.    lCnt := 0;                         {line length counter}
  1217.    BEGIN
  1218.       while (not done) do             {loop until done (EOF mark)}
  1219.       begin
  1220.          GS_FileRead(mFile, Memo_Loc+Memo_Bloks, Mem_Block, 1, Result);
  1221.          inc(Memo_Bloks);
  1222.          mCnt := 0;                   {Counter into disk read buffer}
  1223. {
  1224.                     ┌─────────────────────────────────────┐
  1225.                     │  Start reading and processing the   │
  1226.                     │  sequential memo blocks until EOF   │
  1227.                     │  mark is found.                     │
  1228.                     └─────────────────────────────────────┘
  1229. }
  1230.          while (mCnt < GS_dBase_MaxMemoRec) and
  1231.                (done = false) do
  1232. {
  1233.                  ┌────────────────────────────────────────────┐
  1234.                  │   Repeat the following until you find an   │
  1235.                  │   End-of-Memo condition.  Read the next    │
  1236.                  │   block each time mCnt reaches 512 bytes   │
  1237.                  │   (GS_dBase_MaxMemoRec.  Group the memo    │
  1238.                  │   as a series of lines no greater than     │
  1239.                  │   Memo_Width long.                         │
  1240.                  └────────────────────────────────────────────┘
  1241. }
  1242.          begin
  1243.  
  1244.             case Mem_Block[mCnt] of   {Check for control characters}
  1245.  
  1246.                $1A : begin
  1247.                         done := true; {End of Memo field}
  1248.                         if Memo_Store.Work_line^.Valu_Line = '' then
  1249.                            Memo_Store.Rel_Line_Mem(Memo_Store.Active_Line);
  1250.                      end;
  1251.  
  1252.                $8D : begin            {Soft Return (Wordstar and dBase editor)}
  1253.                         if (Memo_Store.Work_Line^.Valu_Line[lCnt] <> ' ') and
  1254.                            (Memo_Store.Work_Line^.Valu_Line[lCnt] <> '-') and
  1255.                            (lCnt > 0) then
  1256.                         begin
  1257.                            inc(lCnt); {Add to line length count}
  1258.                            Memo_Store.Work_Line^.Valu_Line[lcnt] := ' ';
  1259.                                       {Insert a space in storage}
  1260.                            Memo_Store.Work_Line^.Valu_Line[0] := chr(lcnt);
  1261.                         end;
  1262.                      end;
  1263.  
  1264.                $0A : begin            {Linefeed}
  1265.                      end;             {Ignore these characters}
  1266.  
  1267.                $0D : begin            {Hard Return}
  1268.                         With Memo_Store do
  1269.                         begin
  1270.                            Work_Line^.Return_Cod := $0D;
  1271.                            Work_Line := Get_Line_Mem(Edit_Lgth);
  1272.                            inc(Memo_Store.Active_Line);
  1273.                            lCnt := 0;
  1274.                         end;
  1275.                      end;
  1276.                else                   {Here for other characters}
  1277.                begin
  1278.                   inc(lCnt);          {Add to line length count}
  1279.                   Memo_Store.Work_Line^.Valu_Line[lcnt] :=
  1280.                                       chr(Mem_Block[mCnt]);
  1281.                                       {Insert the character in storage}
  1282.                   Memo_Store.Work_Line^.Valu_Line[0] := chr(lcnt);
  1283.                end;
  1284.             end;
  1285.             inc(mCnt);                {Step to next input buffer location}
  1286.  
  1287.             if lCnt > Memo_Store.Edit_Lgth then
  1288.                                       {If lcnt longer than Memo_Width, you}
  1289.                                       {must word wrap to Memo_Width length}
  1290.                                       {or less}
  1291.             begin
  1292.                while (Memo_Store.Work_Line^.Valu_Line[lCnt] <> ' ') and
  1293.                      (Memo_Store.Work_Line^.Valu_Line[lCnt] <> '-') and
  1294.                      (lCnt > 0) do dec(lCnt);
  1295.                                       {Repeat search for space or hyphen until}
  1296.                                       {found or current line exhausted}
  1297.                if (lCnt = 0) then
  1298.                   lcnt := length(Memo_Store.Work_Line^.Valu_Line) - 1;
  1299.                                       {If no break point, truncate line}
  1300.                with Memo_Store do
  1301.                begin
  1302.                   Temp_Line := Work_Line^.Valu_Line;
  1303.                   system.delete(Temp_Line,1,lCnt);
  1304.                   if lCnt > Memo_Store.Edit_Lgth then
  1305.                      lCnt := Memo_Store.Edit_Lgth;
  1306.                   Work_Line^.Valu_Line[0] := chr(lcnt);
  1307.                                       {Get string up to cursor to split line}
  1308.                   Work_Line := Get_Line_Mem(Edit_Lgth);
  1309.                   inc(Memo_Store.Active_Line);
  1310.                   Work_Line^.Return_Cod := $8D;
  1311.                                       {Insert soft return character}
  1312.                   Work_Line^.Valu_Line  := Temp_Line;
  1313.                   lCnt := length(Work_Line^.Valu_Line);
  1314.                end;
  1315.             end;
  1316.          end;
  1317.       END;
  1318.    end;
  1319. END;                        { Get Memo Field }
  1320.  
  1321. Procedure GS_dBFld_Objt.MemoEdit;
  1322. begin
  1323.    Memo_Store.Edit;
  1324. end;
  1325.  
  1326. Function GS_dBFld_Objt.MemoLines : integer;
  1327. begin
  1328.    MemoLines := Memo_Store.Total_Lines;
  1329. end;
  1330.  
  1331. Procedure GS_dBFld_Objt.MemoWidth(l : integer);
  1332. begin
  1333.    Memo_Store.Edit_Lgth := l;
  1334. end;
  1335.  
  1336. Function GS_dBFld_Objt.MemoPut : string;
  1337. const
  1338.    EOFMark : byte = $1A;              {End of disk file code}
  1339. var
  1340.    bCnt,                              {Will hold bytes in memo field}
  1341.    lCnt,                              {Counter for line length in characters}
  1342.    mCnt,
  1343.    tcnt  :  longint;                  {Counter for input buffer char position}
  1344.    Result  : word;                    {BlockWrite number of bytes written}
  1345.    i     : longint;                   {Working variable}
  1346.    Mem_Block : array [0..GS_dBase_MaxMemoRec*2] of byte;
  1347.                                       {Output buffer}
  1348.    valu  : string[10];                {work string to convert block number}
  1349. BEGIN                       { Put Memo Field }
  1350.    bCnt := Memo_Store.Byte_Count;     {Get count of bytes in memo field}
  1351.    bCnt := bcnt div GS_dBase_MaxMemoRec;
  1352.                                       {Get number of blocks required}
  1353.    inc(bCnt);                         {Adjust from zero}
  1354.    if bCnt > Memo_Bloks then
  1355.    begin
  1356.       GS_FileRead(mFile, 0, Mem_Block, 1, Result);
  1357.                                       {read a block from the .DBT}
  1358.       Move(Mem_Block[0],Memo_Loc,4);
  1359.                                       {Get next block number to append}
  1360.    end;
  1361.    Memo_Bloks := bCnt;                {Set blocks written count}
  1362.    lCnt := 0;                         {line length counter}
  1363.    mCnt := 0;                         {Counter into disk write buffer}
  1364.    tCnt := Memo_Loc;
  1365. {
  1366.                     ┌─────────────────────────────────────┐
  1367.                     │  Start reading and processing the   │
  1368.                     │  sequential memo blocks until EOF   │
  1369.                     │  mark is found.                     │
  1370.                     └─────────────────────────────────────┘
  1371. }
  1372.       with Memo_Store do
  1373.       begin
  1374.          Work_Line := First_Line;
  1375.          while (Work_Line <> nil) do
  1376.          begin
  1377.             move(Work_Line^.Valu_Line[1],Mem_Block[mCnt],
  1378.                  length(Work_Line^.Valu_Line));
  1379.             mCnt := mCnt + length(Work_Line^.Valu_Line);
  1380.             if Work_Line^.Next_Line <> nil then
  1381.             begin
  1382.                Mem_Block[mCnt] := Work_Line^.Return_Cod;
  1383.                Mem_Block[mCnt+1] := $0A;
  1384.                inc(mCnt,2);
  1385.             end;
  1386.             Work_Line := Work_Line^.Next_Line;
  1387.             if (mCnt > GS_dBase_MaxMemoRec) then
  1388.             begin
  1389.                GS_FileWrite(mFile,tcnt,Mem_Block,1, Result);
  1390.                                       {read a block from the .DBT}
  1391.                inc(tcnt);
  1392.                mCnt := mCnt mod GS_dBase_MaxMemoRec;
  1393.                                       {Get excess buffer length used}
  1394.                Move(Mem_Block[GS_dBase_MaxMemoRec],Mem_Block[0],mCnt);
  1395.                                       {Move excess to beginning of buffer}
  1396.             end;
  1397.          end;
  1398.          Mem_Block[mCnt] := EOFMark;
  1399.          FillChar(Mem_Block[succ(mcnt)],GS_dBase_MaxMemoRec - mcnt,#0);
  1400.          GS_FileWrite(mFile,tcnt,Mem_Block,1, Result);
  1401.                                       {Write the last block to the .DBT}
  1402.          i := GS_FileSize(mFile);
  1403.          FillChar(Mem_Block,GS_dBase_MaxMemoRec,#0);
  1404.          Move(i,Mem_Block[0],4);
  1405.          GS_FileWrite(mFile,0,Mem_Block,1, Result);
  1406.                                       {Write the block to the .DBT.  It will}
  1407.                                       {point to the next available block};
  1408.    end;
  1409.    Str(Memo_Loc:10,valu);
  1410.    MemoPut := valu;
  1411. end;
  1412.  
  1413. Procedure GS_dBFld_Objt.StatusUpdate(statword1,statword2,statword3 : longint);
  1414. begin
  1415. end;
  1416.  
  1417.  
  1418. end.
  1419.  
  1420.  
  1421.